package secondriver.ccs.parallel;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

/**
 * Author : secondriver
 */
public final class CcsCompute extends RecursiveTask<List<String>> implements CcsCommon {

    private static final int DEFAULT_STEP = 5;

    private final int edge;
    private int step = DEFAULT_STEP;
    private int sidStartInclude;
    private int sidEndExclude;

    /**
     * 计算指定范围的任务
     *
     * @param edge
     * @param step            default 5
     * @param sidStartInclude start from 0
     * @param sidEndExclude   end to pow(2,edge)
     */
    public CcsCompute(int edge, int step, int sidStartInclude, int sidEndExclude) {
        this.edge = edge;
        this.step = step;
        if (step < DEFAULT_STEP) {
            throw new IllegalArgumentException("step must be >=" + DEFAULT_STEP);
        }
        int max = (int) Math.pow(MOD_TWO, edge);
        if (sidStartInclude >= sidEndExclude || sidStartInclude < 0 || sidEndExclude < 0 || sidStartInclude > max || sidEndExclude > max) {
            throw new IllegalArgumentException("0 <= sidStartInclude < sidEndExclude <=max ");
        }
        this.sidStartInclude = sidStartInclude;
        this.sidEndExclude = sidEndExclude;
    }

    public CcsCompute(int edge, int step) {
        this(edge, step, 0, (int) Math.pow(MOD_TWO, edge));
    }

    public CcsCompute(int edge) {
        this(edge, DEFAULT_STEP);
    }

    @Override
    protected List<String> compute() {
        List<String> fileNameList = new ArrayList<>();
        if (sidEndExclude - sidStartInclude <= step) {
            for (int sid = sidEndExclude; sid < sidEndExclude; sid++) {
                CcsComputeTaskUnit taskUnit = new CcsComputeTaskUnit(edge, sid);
                ForkJoinTask<String> joinTask = taskUnit.fork();
                String fileName = joinTask.join();
                if (!NO_FILE.equals(fileName)) {
                    fileNameList.add(fileName);
                }
            }
        } else {
            List<ForkJoinTask<List<String>>> forkJoinTaskList = new ArrayList<>();
            CcsCompute left = new CcsCompute(edge, step, sidStartInclude, sidStartInclude + step);
            CcsCompute right = new CcsCompute(edge, step, sidStartInclude + step, sidEndExclude);

            forkJoinTaskList.add(left.fork());
            forkJoinTaskList.add(right.fork());

            for (ForkJoinTask<List<String>> task : forkJoinTaskList) {
                List<String> fileNames = task.join();
                fileNames.forEach(fileName -> fileNameList.add(fileName));
            }
        }
        return fileNameList;
    }
}
